package me.stone.stanimeclient.core.ui.adapters

import android.content.Context
import android.graphics.Rect
import android.graphics.Typeface
import android.os.Build
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
import androidx.recyclerview.widget.RecyclerView.LayoutParams
import me.stone.stanimeclient.core.common.di.DiskExecutor
import me.stone.stanimeclient.core.common.extensions.dip
import me.stone.stanimeclient.core.model.FanEpisodeItem
import me.stone.stanimeclient.core.ui.R
import me.stone.stanimeclient.core.ui.adapters.base.AbsSelectStateAdapter
import me.stone.stanimeclient.core.ui.adapters.holder.DefaultViewHolder
import me.stone.stanimeclient.core.ui.databinding.ItemEpisodeTextBinding
import timber.log.Timber
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlin.math.ceil
import kotlin.math.roundToInt

class FanEpisodeAdapter @Inject constructor(
    @DiskExecutor backExecutor: Executor,
): AbsSelectStateAdapter<FanEpisodeItem, DefaultViewHolder>(
    backExecutor = backExecutor,
    diffCallback = DIFF_CALLBACK
) {

    private enum class EpisodeSortType {
        ASC, DESC
    }

    private var sortType: EpisodeSortType = EpisodeSortType.ASC
        set(value) {
            if (field == value) return
            field = value
            notifyItemRangeChanged(0, itemCount)
            mSelectItemPos?.takeIf { it >= 0 }?.let { pos ->
                mRecyclerView?.get()?.let { view ->
                    Timber.d("scroll to pos: $pos")
                    view.post { view.scrollToPosition(pos) }
                }
            }
        }

    fun toSortASC() {
        sortType = EpisodeSortType.ASC
    }

    fun toSortDESC() {
        sortType = EpisodeSortType.DESC
    }

    override val mSelectItemPos: Int?
        get() = when (sortType) {
            EpisodeSortType.ASC -> super.mSelectItemPos
            EpisodeSortType.DESC -> super.mSelectItemPos?.let {
                itemCount - it - 1
            }
        }

    override fun getItem(position: Int): FanEpisodeItem {
        return super.getItem(
            when (sortType) {
                EpisodeSortType.ASC -> position
                EpisodeSortType.DESC -> itemCount - position - 1
            }
        )
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DefaultViewHolder {
        return DefaultViewHolder(createTextView(parent))
    }

    override fun bindViewData(holder: DefaultViewHolder, position: Int, item: FanEpisodeItem) {
        (holder.itemView as TextView).text = item.episodeName
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        recyclerView.setHasFixedSize(true)
        val dp4 = 4f.dip.roundToInt()
        if (recyclerView.paddingTop == 0 || recyclerView.paddingStart == 0) {
            recyclerView.setPaddingRelative(dp4, dp4, dp4, dp4)
        }
        if (recyclerView.itemDecorationCount == 0) {
            recyclerView.addItemDecoration(object : ItemDecoration() {
                override fun getItemOffsets(
                    outRect: Rect,
                    view: View,
                    parent: RecyclerView,
                    state: RecyclerView.State
                ) {
                    outRect.set(dp4, dp4, dp4, dp4)
                }
            })
        }
        redrawRecyclerView()
    }

    override fun onItemViewSelected(view: View) {
        with(view as TextView) {
            isSelected = true
            typeface = Typeface.DEFAULT_BOLD
        }
    }

    override fun onItemViewUnSelect(view: View) {
        with(view as TextView) {
            isSelected = false
            typeface = Typeface.DEFAULT
        }
    }

    override fun updateSelected(list: List<FanEpisodeItem>) {
        if (list.isEmpty()) return
        val selectedPair = mSelectedItemPair ?: return
        val newPos = list.indexOfFirst {
            DIFF_CALLBACK.areItemsTheSame(selectedPair.second, it) &&
                DIFF_CALLBACK.areContentsTheSame(selectedPair.second, it)
        }
        if (newPos != -1) {
            mSelectedItemPair = newPos to list[newPos]
        }
    }

    override fun submitList(list: List<FanEpisodeItem>?) {
        super.submitList(list) {
            redrawRecyclerView()
        }
    }

    override fun submitList(list: List<FanEpisodeItem>?, commitCallback: Runnable?) {
        super.submitList(list) {
            redrawRecyclerView()
            commitCallback?.run()
        }
    }

    private fun redrawRecyclerView() {
        val recyclerView = mRecyclerView?.get() ?: return
        recyclerView.post {
            val layoutManager = recyclerView.layoutManager as? RedrawLayoutManager
            if (layoutManager == null) {
                (recyclerView.layoutManager as? GridLayoutManager)?.apply {
                    spanCount = if (itemCount > 21) 2 else 1
                }
                return@post
            }

            val view = layoutManager.findViewByPosition(
                layoutManager.findLastVisibleItemPosition()
            ) ?: return@post

            val padding = 8f.dip
            val lines = ceil(itemCount / 3f).toInt().coerceAtMost(10)
            val dynamicHeight = ceil((view.height + padding) * lines + padding).toInt()
            recyclerView.layoutParams.height = dynamicHeight
            recyclerView.post { recyclerView.requestLayout() }
        }
    }

    private class RedrawLayoutManager(context: Context, span: Int): GridLayoutManager(context, span)

    companion object {
        private const val SPAN_COUNT = 3

        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<FanEpisodeItem>() {
            override fun areItemsTheSame(oldItem: FanEpisodeItem, newItem: FanEpisodeItem): Boolean {
                return oldItem.episodeName == newItem.episodeName &&
                        oldItem.fanId == newItem.fanId
            }

            override fun areContentsTheSame(oldItem: FanEpisodeItem, newItem: FanEpisodeItem): Boolean {
                return oldItem == newItem
            }
        }

        @JvmStatic
        private fun createTextView(parent: ViewGroup): TextView {
//            return TextView(parent.context).apply {
//                layoutParams = ConstraintLayout.LayoutParams(
//                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT
//                )
//                gravity = Gravity.CENTER
//                4f.dip.roundToInt().also { setPaddingRelative(it, it * 2, it, it * 2) }
//                setBackgroundResource(R.drawable.shape_episode_item)
//                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//                    setTextColor(parent.context.getColor(R.color.md_theme_onSurface))
//                }
//            }
            return ItemEpisodeTextBinding.inflate(
                LayoutInflater.from(parent.context), parent, false
            ).root
        }

        @JvmStatic
        fun attachRedrawManager(recyclerView: RecyclerView) {
            recyclerView.layoutManager = RedrawLayoutManager(recyclerView.context, SPAN_COUNT)
        }

        @JvmStatic
        fun attachGridManger(recyclerView: RecyclerView, spanCount: Int = SPAN_COUNT) {
            recyclerView.layoutManager = GridLayoutManager(recyclerView.context, spanCount)
        }
    }

}